// === SECTION DOS PERSONAGENS ===
const characterData = [
{
id: "1",
name: "Soul Master",
description:
"Especialista em combate corpo a corpo, combinando força bruta com o poder de suas lâminas encantadas. Um verdadeiro titã no campo de batalha.",
videoSrc: "/images/assets/chars/SoulMaster.jpg",
iconSrc: "/images/assets/chars/SoulMaster.jpg",
},
{
id: "2",
name: "Fairy Elf",
description:
"Arqueira ágil e precisa, abençoada pela natureza. Suas flechas encantam os inimigos e curam os aliados, dominando o combate à distância.",
videoSrc: "/images/assets/chars/FairyElf.jpg",
iconSrc: "/images/assets/chars/FairyElf.jpg",
},
{
id: "3",
name: "Dark Lord",
description:
"Mestre das artes arcanas, capaz de conjurar magias devastadoras que controlam os elementos e aniquilam exércitos inteiros com um único gesto.",
videoSrc: "/images/assets/chars/DarkLord.png",
iconSrc: "/images/assets/chars/DarkLord.png",
},
{
id: "5",
name: "Rune Wizard",
description:
"Mestre das artes arcanas, capaz de conjurar magias devastadoras que controlam os elementos e aniquilam exércitos inteiros com um único gesto.",
videoSrc: "/images/assets/chars/RuneWizard.png",
iconSrc: "/images/assets/chars/RuneWizard.png",
},
{
id: "6",
name: "Illusion Knight",
description:
"Mestre das artes arcanas, capaz de conjurar magias devastadoras que controlam os elementos e aniquilam exércitos inteiros com um único gesto.",
videoSrc: "/images/assets/chars/IllusionKnight.jpg",
iconSrc: "/images/assets/chars/IllusionKnight.jpg",
},
{
id: "7",
name: "Alchemist",
description:
"Mestre das artes arcanas, capaz de conjurar magias devastadoras que controlam os elementos e aniquilam exércitos inteiros com um único gesto.",
videoSrc: "/images/assets/chars/Alchemist.png",
iconSrc: "/images/assets/chars/Alchemist.png",
},
];
// === CHARACTER SELECTOR ===
function initCharacterSelector() {
const videoEl = document.getElementById("character-video");
const nameEl = document.getElementById("character-name");
const descriptionEl = document.getElementById("character-description");
const viewportEl = document.getElementById("selector-viewport");
if (!viewportEl || !videoEl || !nameEl || !descriptionEl) {
console.error("Elementos do seletor de personagem não encontrados!");
return;
}
const trackEl = document.createElement("div");
trackEl.style.display = "flex";
trackEl.style.alignItems = "center";
trackEl.style.gap = "1rem";
trackEl.style.padding = "1rem";
viewportEl.appendChild(trackEl);
let activeCharacterId = null;
function showCharacter(characterId) {
if (activeCharacterId === characterId) return;
const character = characterData.find((c) => c.id === characterId);
if (!character) return;
nameEl.textContent = character.name;
descriptionEl.textContent = character.description;
videoEl.src = character.videoSrc;
// videoEl.load();
const oldActiveIcon = trackEl.querySelector(".active");
if (oldActiveIcon) oldActiveIcon.classList.remove("active");
const newActiveIcon = trackEl.querySelector(`[data-id="${characterId}"]`);
if (newActiveIcon) {
newActiveIcon.classList.add("active");
newActiveIcon.scrollIntoView({
behavior: "smooth",
block: "nearest",
inline: "center",
});
}
activeCharacterId = characterId;
}
characterData.forEach((character) => {
const icon = document.createElement("div");
icon.className = "character-icon";
icon.setAttribute("data-id", character.id);
icon.style.backgroundImage = `url(${character.iconSrc})`;
icon.addEventListener("click", () => showCharacter(character.id));
trackEl.appendChild(icon);
});
if (characterData.length > 0) {
showCharacter(characterData[0].id);
}
let isDown = false;
let startX;
let scrollLeft;
viewportEl.addEventListener("mousedown", (e) => {
isDown = true;
viewportEl.classList.add("active-drag");
startX = e.pageX - viewportEl.offsetLeft;
scrollLeft = viewportEl.scrollLeft;
});
const stopDragging = () => {
isDown = false;
viewportEl.classList.remove("active-drag");
};
viewportEl.addEventListener("mouseleave", stopDragging);
viewportEl.addEventListener("mouseup", stopDragging);
viewportEl.addEventListener("mousemove", (e) => {
if (!isDown) return;
e.preventDefault();
const x = e.pageX - viewportEl.offsetLeft;
const walk = (x - startX) * 2;
viewportEl.scrollLeft = scrollLeft - walk;
});
}
// === SECTIO RANKINGS ===
const rankingsData = {
players: [
{
rank: 1,
name: "IceWarrior",
level: 400,
class: "Blade Knight",
guild: "IceLegion",
},
{
rank: 2,
name: "FrostMage",
level: 395,
class: "Soul Master",
guild: "FrozenSouls",
},
{
rank: 3,
name: "BloodElf",
level: 387,
class: "Muse Elf",
guild: "ArcticKnights",
},
{
rank: 4,
name: "Shadow",
level: 385,
class: "Magic Gladiator",
guild: "IceLegion",
},
{
rank: 5,
name: "Reaper",
level: 382,
class: "Dark Lord",
guild: "Titans",
},
],
guilds: [
{
rank: 1,
name: "IceLegion",
leader: "IceWarrior",
members: 28,
logoSrc: "path/to/your/guild_logos/icelegion.png",
},
{
rank: 2,
name: "FrozenSouls",
leader: "FrostMage",
members: 25,
logoSrc: "path/to/your/guild_logos/frozensouls.png",
},
{
rank: 3,
name: "ArcticKnights",
leader: "BloodElf",
members: 22,
logoSrc: "path/to/your/guild_logos/knights.png",
},
],
huntPoints: [
{ rank: 1, name: "HunterX", points: 152340, class: "Muse Elf" },
{ rank: 2, name: "Beast", points: 149800, class: "Blade Knight" },
{ rank: 3, name: "Stalker", points: 135000, class: "Magic Gladiator" },
],
};
const rankingConfigs = {
players: {
title: "Top Players",
columns: [
{ label: "Pos.", className: "pos", render: (item) => `#${item.rank}` },
{ label: "Nome", className: "name", render: (item) => item.name },
{ label: "Classe", className: "class", render: (item) => item.class },
{ label: "Level", className: "level", render: (item) => item.level },
{
label: "Guilda",
className: "guild",
render: (item) => item.guild || "-",
},
],
},
guilds: {
title: "Top Guilds",
columns: [
{ label: "Pos.", className: "pos", render: (item) => `#${item.rank}` },
{
label: "Mark",
className: "mark",
render: (item) =>
`
`,
},
{ label: "Nome", className: "name-guild", render: (item) => item.name },
{ label: "Líder", className: "leader", render: (item) => item.leader },
],
},
huntPoints: {
title: "Hunt Points",
columns: [
{ label: "Pos.", className: "pos", render: (item) => `#${item.rank}` },
{ label: "Nome", className: "name", render: (item) => item.name },
{ label: "Classe", className: "class", render: (item) => item.class },
{
label: "Pontos",
className: "points",
render: (item) => item.points.toLocaleString(),
},
],
},
};
function initRankingSystem() {
const tabsContainer = document.getElementById("rankings-tabs");
const tableHeader = document.getElementById("ranking-table-header");
const tableBody = document.getElementById("ranking-table-body");
if (!tabsContainer || !tableHeader || !tableBody) return;
function updateRankingView(rankType) {
const config = rankingConfigs[rankType];
const data = rankingsData[rankType];
if (!config || !data) {
console.error(
`Configuração ou dados para o ranking '${rankType}' não encontrados.`
);
return;
}
tableHeader.innerHTML = config.columns
.map(
(col) => `
${col.label}
`
)
.join("");
tableBody.innerHTML = "";
if (data.length === 0) {
tableBody.innerHTML = `Nenhum dado neste ranking ainda.
`;
return;
}
const fragment = document.createDocumentFragment();
data.forEach((item) => {
const row = document.createElement("div");
row.className =
item.rank <= 3 ? `ranking-row rank-${item.rank}` : "ranking-row";
const cellFragment = document.createDocumentFragment();
config.columns.forEach((col) => {
const cell = document.createElement("div");
cell.className = `ranking-cell ${col.className}`;
cell.innerHTML = col.render(item);
cellFragment.appendChild(cell);
});
row.appendChild(cellFragment);
fragment.appendChild(row);
});
tableBody.appendChild(fragment);
}
tabsContainer.addEventListener("click", (e) => {
const button = e.target.closest("button.rank-tab");
if (button) {
const rankType = button.dataset.rankType;
tabsContainer.querySelector(".active")?.classList.remove("active");
button.classList.add("active");
updateRankingView(rankType);
}
});
const initialTab = tabsContainer.querySelector(".rank-tab");
if (initialTab) {
initialTab.click();
}
}
// === ANIMAÇÕES DE SCROLL ===
const observerOptions = {
threshold: 0.1,
rootMargin: "0px 0px -50px 0px",
};
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
}
});
}, observerOptions);
// === CAROUSEL ===
function initRankingSystem() {
const tabsContainer = document.getElementById("rankings-tabs");
const tableHeader = document.getElementById("ranking-table-header");
const tableBody = document.getElementById("ranking-table-body");
if (!tabsContainer || !tableHeader || !tableBody) return;
function updateRankingView(rankType) {
const config = rankingConfigs[rankType];
const data = rankingsData[rankType];
if (!config || !data) return;
tableHeader.innerHTML = config.columns
.map(
(col) => `${col.label}
`
)
.join("");
tableBody.innerHTML = "";
if (data.length === 0) {
tableBody.innerHTML = `Nenhum dado neste ranking ainda.
`;
return;
}
const fragment = document.createDocumentFragment();
data.forEach((item) => {
const row = document.createElement("div");
row.className =
item.rank <= 3 ? `ranking-row rank-${item.rank}` : "ranking-row";
config.columns.forEach((col) => {
const cell = document.createElement("div");
cell.className = `ranking-cell ${col.className}`;
cell.innerHTML = col.render(item);
row.appendChild(cell);
});
fragment.appendChild(row);
});
tableBody.appendChild(fragment);
}
tabsContainer.addEventListener("click", (e) => {
const button = e.target.closest("button.rank-tab");
if (button) {
const rankType = button.dataset.rankType;
tabsContainer.querySelector(".active")?.classList.remove("active");
button.classList.add("active");
updateRankingView(rankType);
}
});
const initialTab = tabsContainer.querySelector(".rank-tab");
if (initialTab) initialTab.click();
}
// === FAQ ACCORDION ===
function initFAQ() {
const accordion = document.getElementById("faq-accordion");
if (!accordion) return;
const faqItems = accordion.querySelectorAll(".faq-item");
faqItems.forEach((item) => {
const toggle = item.querySelector(".faq-toggle");
toggle.addEventListener("click", () => {
const isOpen = item.classList.contains("is-open");
faqItems.forEach((otherItem) => {
otherItem.classList.remove("is-open");
});
if (!isOpen) {
item.classList.add("is-open");
}
});
});
}
// === CAROUSEL ===
function initCarousel() {
const track = document.getElementById("carousel-track");
const prevButton = document.getElementById("prev-button");
const nextButton = document.getElementById("next-button");
if (!track || !prevButton || !nextButton) return;
const slides = Array.from(track.children);
let currentIndex = 0;
let isDragging = false;
let startPos = 0;
let currentTranslate = 0;
let prevTranslate = 0;
let animationID;
function getVisibleSlidesCount() {
if (window.innerWidth >= 768) return 3;
return 1;
}
function updateCarousel() {
const visibleSlides = getVisibleSlidesCount();
const totalSlides = slides.length;
if (totalSlides === 0) return;
const slideWidth = slides[0].offsetWidth;
const gap = 24;
const moveDistance = slideWidth + gap;
currentTranslate = -currentIndex * moveDistance;
prevTranslate = currentTranslate;
track.style.transform = `translateX(${currentTranslate}px)`;
track.style.transition = "transform 0.5s ease-in-out";
prevButton.disabled = currentIndex === 0;
nextButton.disabled = currentIndex >= totalSlides - visibleSlides;
}
function moveToNextSlide() {
const visibleSlides = getVisibleSlidesCount();
const totalSlides = slides.length;
if (currentIndex < totalSlides - visibleSlides) {
currentIndex++;
updateCarousel();
}
}
function moveToPrevSlide() {
if (currentIndex > 0) {
currentIndex--;
updateCarousel();
}
}
function getPositionX(event) {
return event.type.includes("mouse")
? event.pageX
: event.touches[0].clientX;
}
function dragStart(event) {
isDragging = true;
startPos = getPositionX(event);
animationID = requestAnimationFrame(animation);
track.style.transition = "none";
track.classList.add("grabbing");
}
function dragMove(event) {
if (isDragging) {
const currentPosition = getPositionX(event);
currentTranslate = prevTranslate + currentPosition - startPos;
}
}
function dragEnd() {
if (!isDragging) return;
isDragging = false;
cancelAnimationFrame(animationID);
const movedBy = currentTranslate - prevTranslate;
if (movedBy < -50) {
moveToNextSlide();
} else if (movedBy > 50) {
moveToPrevSlide();
} else {
track.style.transform = `translateX(${prevTranslate}px)`;
track.style.transition = "transform 0.3s ease-out";
}
track.classList.remove("grabbing");
}
function animation() {
track.style.transform = `translateX(${currentTranslate}px)`;
if (isDragging) requestAnimationFrame(animation);
}
// Event listeners
nextButton.addEventListener("click", moveToNextSlide);
prevButton.addEventListener("click", moveToPrevSlide);
window.addEventListener("resize", () => {
currentIndex = 0;
updateCarousel();
});
slides.forEach((slide) => {
slide.addEventListener("click", (e) => {
const movedBy = currentTranslate - prevTranslate;
if (Math.abs(movedBy) > 5) {
e.preventDefault();
}
});
});
track.addEventListener("mousedown", dragStart);
track.addEventListener("touchstart", dragStart, { passive: true });
track.addEventListener("mouseup", dragEnd);
track.addEventListener("mouseleave", dragEnd);
track.addEventListener("touchend", dragEnd);
track.addEventListener("mousemove", dragMove);
track.addEventListener("touchmove", dragMove, { passive: true });
updateCarousel();
}
// === CARROSSEL DE FEATURES ===
function initFeaturesCarousel() {
const track = document.getElementById("features-carousel-track");
const prevButton = document.getElementById("features-prev-button");
const nextButton = document.getElementById("features-next-button");
if (!track || !prevButton || !nextButton) return;
const slides = Array.from(track.children);
let currentIndex = 0;
let isDragging = false;
let startPos = 0;
let currentTranslate = 0;
let prevTranslate = 0;
let animationID;
function getVisibleSlidesCount() {
if (window.innerWidth >= 768) return 3;
return 1;
}
function updateCarousel() {
const visibleSlides = getVisibleSlidesCount();
const totalSlides = slides.length;
if (totalSlides === 0) return;
const slideWidth = slides[0].offsetWidth;
const gap = 24;
const moveDistance = slideWidth + gap;
currentTranslate = -currentIndex * moveDistance;
prevTranslate = currentTranslate;
track.style.transform = `translateX(${currentTranslate}px)`;
track.style.transition = "transform 0.5s ease-in-out";
prevButton.disabled = currentIndex === 0;
nextButton.disabled = currentIndex >= totalSlides - visibleSlides;
}
function moveToNextSlide() {
const visibleSlides = getVisibleSlidesCount();
const totalSlides = slides.length;
if (currentIndex < totalSlides - visibleSlides) {
currentIndex++;
updateCarousel();
}
}
function moveToPrevSlide() {
if (currentIndex > 0) {
currentIndex--;
updateCarousel();
}
}
function getPositionX(event) {
return event.type.includes("mouse")
? event.pageX
: event.touches[0].clientX;
}
function dragStart(event) {
isDragging = true;
startPos = getPositionX(event);
animationID = requestAnimationFrame(animation);
track.style.transition = "none";
track.classList.add("grabbing");
}
function dragMove(event) {
if (isDragging) {
const currentPosition = getPositionX(event);
currentTranslate = prevTranslate + currentPosition - startPos;
}
}
function dragEnd() {
if (!isDragging) return;
isDragging = false;
cancelAnimationFrame(animationID);
const movedBy = currentTranslate - prevTranslate;
if (movedBy < -50) {
moveToNextSlide();
} else if (movedBy > 50) {
moveToPrevSlide();
} else {
track.style.transform = `translateX(${prevTranslate}px)`;
track.style.transition = "transform 0.3s ease-out";
}
track.classList.remove("grabbing");
}
function animation() {
track.style.transform = `translateX(${currentTranslate}px)`;
if (isDragging) requestAnimationFrame(animation);
}
// Event listeners
nextButton.addEventListener("click", moveToNextSlide);
prevButton.addEventListener("click", moveToPrevSlide);
window.addEventListener("resize", () => {
currentIndex = 0;
updateCarousel();
});
slides.forEach((slide) => {
slide.addEventListener("click", (e) => {
const movedBy = currentTranslate - prevTranslate;
if (Math.abs(movedBy) > 5) {
e.preventDefault();
}
});
});
track.addEventListener("mousedown", dragStart);
track.addEventListener("touchstart", dragStart, { passive: true });
track.addEventListener("mouseup", dragEnd);
track.addEventListener("mouseleave", dragEnd);
track.addEventListener("touchend", dragEnd);
track.addEventListener("mousemove", dragMove);
track.addEventListener("touchmove", dragMove, { passive: true });
updateCarousel();
}
// === NAVEGAÇÃO SUAVE ===
function initSmoothNavigation() {
const navLinks = document.querySelectorAll('nav a[href^="#"]');
navLinks.forEach((link) => {
link.addEventListener("click", function (e) {
e.preventDefault();
const targetId = this.getAttribute("href").substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
const offsetTop = targetElement.offsetTop - 80;
window.scrollTo({
top: offsetTop,
behavior: "smooth",
});
}
});
});
}
// === INICIALIZAÇÃO ===
document.addEventListener("DOMContentLoaded", function () {
// Inicializar observador de animações
const animatedElements = document.querySelectorAll(
".fade-in, .slide-in-left, .slide-in-right"
);
animatedElements.forEach((element) => {
observer.observe(element);
});
// Adicionar classe visible aos elementos hero
setTimeout(() => {
const heroElements = document.querySelectorAll(
"#home .fade-in, #home .slide-in-left, #home .slide-in-right"
);
heroElements.forEach((element) => {
element.classList.add("visible");
});
}, 300);
// Inicializar componentes
initCarousel();
initFeaturesCarousel();
initCharacterSelector();
initRankingSystem();
initFAQ();
initSmoothNavigation();
});
// === CARREGAMENTO DA PÁGINA ===
window.addEventListener("load", function () {
document.body.style.opacity = "0";
document.body.style.transition = "opacity 0.5s ease-in-out";
setTimeout(() => {
document.body.style.opacity = "1";
}, 100);
});
// === OTIMIZAÇÃO MOBILE ===
const isMobile = window.innerWidth <= 768;
if (isMobile) {
const parallaxElements = document.querySelectorAll(".parallax-element");
parallaxElements.forEach((element) => {
element.style.transform = "none";
});
}
// === SISTEMA DE PARTÍCULAS INTELIGENTE OTIMIZADO ===
function initParticles() {
const particles = document.querySelectorAll(".particle");
particles.forEach((particle, index) => {
const imageName = particle.getAttribute("data-image");
const delay = particle.getAttribute("data-delay") || "0s";
// Aplica a imagem de fundo
particle.style.backgroundImage = `url('assets/images/particles/${imageName}')`;
// Aplica o delay da animação
particle.style.animationDelay = delay;
// Sistema de distribuição uniforme para 145+ partículas
// Distribui as partículas uniformemente em toda a largura
const totalWidth = 98; // 2% a 98% da largura
const startPosition = 2;
// Calcula posição baseada no índice para distribuição uniforme
let baseLeft;
if (particles.length > 0) {
const spacing = totalWidth / particles.length;
baseLeft = startPosition + index * spacing;
} else {
baseLeft = startPosition + ((index * 2) % totalWidth);
}
// Adiciona pequena randomização para naturalidade
const randomOffset = Math.random() * 4 - 2; // -2% a +2%
// Garante que as partículas não saiam dos limites
const finalLeft = Math.max(1, Math.min(99, baseLeft + randomOffset));
particle.style.left = `${finalLeft}%`;
// Adiciona variação na velocidade da animação baseada na camada
const currentDuration =
parseFloat(getComputedStyle(particle).animationDuration) || 25;
let speedVariation = 0;
// Diferentes velocidades para diferentes tipos de partículas
if (particle.classList.contains("particle-micro")) {
speedVariation = Math.random() * 8 - 4; // ±4s para partículas micro
} else if (particle.classList.contains("particle-extra")) {
speedVariation = Math.random() * 6 - 3; // ±3s para partículas extra
} else if (particle.classList.contains("particle-float")) {
speedVariation = Math.random() * 10 - 5; // ±5s para partículas flutuantes
} else {
speedVariation = Math.random() * 4 - 2; // ±2s para outras partículas
}
particle.style.animationDuration = `${currentDuration + speedVariation}s`;
// Adiciona pequena variação no topo das partículas para mais naturalidade
if (!particle.style.top || particle.style.top === "auto") {
let topVariation = 0;
if (particle.classList.contains("particle-top")) {
topVariation = Math.random() * 15; // 0% a 15%
} else if (particle.classList.contains("particle-middle")) {
topVariation = 25 + Math.random() * 20; // 25% a 45%
} else if (particle.classList.contains("particle-bottom")) {
topVariation = 60 + Math.random() * 20; // 60% a 80%
} else if (particle.classList.contains("particle-micro")) {
topVariation = 40 + Math.random() * 30; // 40% a 70%
} else if (particle.classList.contains("particle-extra")) {
topVariation = 10 + Math.random() * 15; // 10% a 25%
} else {
topVariation = Math.random() * 80; // Distribuição aleatória completa
}
particle.style.top = `${topVariation}%`;
}
});
}
// Inicializa as partículas quando o DOM estiver carregado
document.addEventListener("DOMContentLoaded", initParticles);
// Reinicializa em caso de redimensionamento da tela
window.addEventListener("resize", () => {
setTimeout(initParticles, 100);
});